from __future__ import print_function ## a hack to enable print as a function. This MUST come as the first line.
import json
import logging
import sys
import puza_row as pr
import puza_table as pt

class PuzaStreamTable(pt.PuzaTable):
    def __init__(self):
        pt.PuzaTable.__init__(self)
        self.__length = -1
    
    def InputFile(self, filename =''):
        pt.PuzaTable.InputFile(self, filename)

    def ReadLines(self, func = lambda x:print(x)):
        while True:
            raw_obj = self.StreamInRow()
            if raw_obj != None:               
                r = pr.PuzaRow.Load(raw_obj)
                if r != None:
                    func(r)
            else:
                break
    
    def __length_handler(self, raw_str):
        try:
            self.__length = self.__length + 1
        except:
            pass

    def Length(self):
        if self.input_filename != '' and self.__length == -1:
            logging.info('Start Length')
            self.__length = 0
            self.ReadLines(self.__length_handler)
            logging.info('Finished Length')
        return self.__length
    
    def __len__(self):
        return self.Length()
    
    def OutputFile(self, filename = ''):
        pt.PuzaTable.OutputFile(self, filename)
    
    def __merge_structure(self, row):
        a = row.GetStructure()
        a_set = set(a)
        for item_name in a_set:
            if item_name in self._inner_structure:
                self._inner_structure[item_name]['counts'] = self._inner_structure[item_name]['counts'] + 1
            else:
                self._inner_structure[item_name]= a[item_name]
                self._inner_structure[item_name]['counts'] = 1
                self._inner_structure[item_name]['level'] = a[item_name]['level']
        
    
    def GetStructure(self):
        if self.input_filename != '':
            logging.info('Start to obtain the table structure.')
            self._inner_structure = {}
            self.ReadLines(self.__merge_structure)
            logging.info('Finish to obtain the table structure.')
        return self._inner_structure
    
    @staticmethod
    def Verify(filename = ''):
        A = PuzaStreamTable()
        error = 1
        A.InputFile(filename)
        try:
            A.ReadLines(func = lambda x:json.loads(x))
        except:
            error = 0
        return error
    
    def Rows(self, start_n, end_n):        
        rows_buffer = []
        current_n = 0
        while True:
            raw_obj = self.StreamInRow()
            if raw_obj != None:
                if current_n >= start_n and current_n <= end_n:
                    rows_buffer.append(pr.PuzaRow.Load(raw_obj))
                current_n = current_n + 1
            else:
                break
            if current_n >= end_n:
                break
        return rows_buffer